import java.util.List;

public class CalcArea {


    private static double earthRadiusMeters=6378137.0;
    private static double metersPerDegree=2.0* Math.PI*earthRadiusMeters/360.0;
    private static double radiansPerDegree = Math.PI / 180.0;
    private static double degreesPerRadian=180.0/ Math.PI;

    public  static  void calclateArea(List<double[]> points){
        if(points.size()>2){
            double areaMeters2 = planarPolygonAreaMeters2(points);
            if(areaMeters2>1000000.0){
                areaMeters2 = sphericalPolygonAreaMeters2(points);
            }
            System.out.println("面积为"+areaMeters2/1000000.0+"平方公里");
        }
    }

    private static double sphericalPolygonAreaMeters2(List<double[]> points) {
        double totalAngle = 0.0;
        for (int i=0;i<points.size();++i){
            int j = (i + 1) % points.size();
            int k = (i + 2) % points.size();
            totalAngle += Angle(points.get(i), points.get(j), points.get(k));
        }

        double planarTotalAngle = (points.size() - 2) * 180.0;
        double sphericalExcess = totalAngle - planarTotalAngle;
        if(sphericalExcess>420.0){
            totalAngle = points.size() * 360 - totalAngle;
            sphericalExcess = totalAngle - planarTotalAngle;

        }else if(sphericalExcess>300.0 && sphericalExcess<420.0){
            sphericalExcess = Math.abs(360.0 - sphericalExcess);

        }
        return sphericalExcess * radiansPerDegree * earthRadiusMeters * earthRadiusMeters;
    }

    private static double Angle(double[] p1, double[] p2, double[] p3) {
        double bearing21 = Bearing(p2, p1);
        double bearing23 = Bearing(p2, p3);
        double angle = bearing21 - bearing23;
        if(angle<0.0){
            angle += 360.0;
        }
        return angle;
    }

    private static double Bearing(double[] from, double[] to) {
        double lat1 = from[1] * radiansPerDegree;
        double lon1 = from[0] * radiansPerDegree;
        double lat2 = to[1] * radiansPerDegree;
        double lon2 = to[0] * radiansPerDegree;

        double angle = Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
        if(angle<0.0){
            angle += Math.PI * 2.0;
        }
        angle = angle * degreesPerRadian;
        return angle;
    }

    private static double planarPolygonAreaMeters2(List<double[]> points) {
        double a = 0.0;
        for (int i=0; i<points.size(); ++i){
            int j = (i + 1) % points.size();
            double xi = points.get(i)[0] * metersPerDegree * Math.cos(points.get(i)[1] * radiansPerDegree);
            double yi = points.get(i)[1] * metersPerDegree;
            double xj = points.get(j)[0] * metersPerDegree * Math.cos(points.get(j)[1] * radiansPerDegree);
            double yj = points.get(j)[1] * metersPerDegree;

            a += xi * yj - xj * yi;
        }
        return Math.abs(a / 2.0);
    }


}
